#include <stdlib.h>
#include <string.h>

#include "pear_account.h"
#include "log/pear_log.h"
#include "utils/pear_dump.h"
#include "crypto/pear_key.h"
#include "store/pear_kv_store.h"
#include "crypto/pear_keystore.h"

pr_acc_ctx_t *pr_new_acc_ctx()
{
    pr_acc_ctx_t *act = NULL;

    act = (pr_acc_ctx_t *) malloc(sizeof(*act));
    if (act == NULL)
    {
        PEAR_LOG("malloc pr_acc_ctx_t error\n");
        return NULL;
    }

    memset(act, 0x00, sizeof(*act));

    act->store = pr_new_kv_store(0);
    if (act->store == NULL)
    {
        free(act);
        PEAR_LOG("pr_new_kv_store error\n");
        return NULL;
    }

    return act;
}

pr_account_t *pr_get_account(pr_acc_ctx_t *actx, char *addr)
{
    char *value       = NULL;
    pr_account_t *acc = NULL;

    acc = (pr_account_t *) malloc(sizeof(*acc));
    if (acc == NULL)
    {
        PEAR_LOG("malloc acc error\n");
        return NULL;
    }

    if ((value = actx->store->get(actx->store, addr)) == NULL)
    {
        free(acc);
        free(value);
        return NULL;
    }

    /*serialize ... */
    pr_hex_decode((unsigned char *)acc, (const char *)value, sizeof(*acc) * 2);
    free(value);

    return acc;
}

pr_account_t *pr_set_account(pr_acc_ctx_t *actx, char *addr, pr_account_t *acc)
{
    char accstr[sizeof(pr_account_t) * 2] = {0x00};

    /*serialize ... */
    pr_hex_encode(accstr, (char *)acc, sizeof(*acc));

    return actx->store->set(actx->store, addr, accstr) == NULL ? NULL : acc;
}

pr_account_t *pr_add_account(pr_acc_ctx_t *acc_ctx, char *path, pr_coin_t balance)
{
    char buf[40]      = {0x00};
    char hash_160[20] = {0x00};

    pr_key_t     *key = NULL;
    pr_account_t *acc = NULL;

    acc = (pr_account_t *) malloc(sizeof(*acc));
    if (acc == NULL)
    {
        free(acc_ctx);
        PEAR_LOG("malloc acc error\n");
        return NULL;
    }

    memset(acc, 0x00, sizeof(acc));

    key = pr_new_key();
    if (key == NULL)
    {
        PEAR_LOG("pr_new_key error\n");
        free(acc_ctx);
        free(acc);
        return NULL;
    }

    if (pr_set_keystore(key, path) < 0)
    {
        free(acc);
        free(key);
        free(acc_ctx);
        return NULL;
    }

    acc->balance = (pr_coin_t)balance;
    memcpy(acc->pubkey, key->pubkey, sizeof(key->pubkey));
    pr_hash160((char *)acc->pubkey, sizeof(acc->pubkey), hash_160);
    pr_set_account(acc_ctx, pr_hex_encode(buf, hash_160, sizeof(hash_160)), acc);
    PEAR_LOG("addr: %s\n", buf);
    free(key);
    free(acc_ctx);

    return acc;
}


int pr_account_query(pr_acc_ctx_t *acc_ctx, char *addr)
{
    pr_account_t  *acc = NULL;
    unsigned char buf[sizeof(pr_pubkey_t) * 2] = {0x00};

    printf("addr: %s\n",  addr);

    acc = pr_get_account(acc_ctx, addr);
    if (acc == NULL)
    {
        printf("unknow account addr\n");
    }

    printf("balance:  %ld\n", acc->balance);
    printf("sequence: %ld\n", acc->sequence);
    printf("pubkey:   %s\n",  pr_hex_encode(buf, acc->pubkey, sizeof(acc->pubkey)));

    return 0;
}


